/*
 * Copyright (c) 2004-2006, Volatile-Engine All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the Volatile-Engine nor the
 * names of its contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */
/**
 * 
 */
package com.volatileengine.tests;

import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.vecmath.AxisAngle4f;
import javax.vecmath.Color4f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Point3f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector2f;
import javax.vecmath.Vector3f;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

import com.volatileengine.image.Texture;
import com.volatileengine.image.loader.TextureLoader;
import com.volatileengine.material.SceneMaterial;
import com.volatileengine.material.states.TextureRenderState;
import com.volatileengine.material.xml.SceneMaterialXMLElement;
import com.volatileengine.platform.PlatformManager;
import com.volatileengine.platform.RenderingContext;
import com.volatileengine.renderer.lwjgl.LWJGLPlatform;
import com.volatileengine.resources.IResourceFinder;
import com.volatileengine.scene.Frustum;
import com.volatileengine.scene.InterleavedGeometry;
import com.volatileengine.scene.SceneMesh;
import com.volatileengine.scene.TransformSceneNode;
import com.volatileengine.scene.WindowSurface;
import com.volatileengine.util.Timer;
import com.volatileengine.xml.XMLLoader;

/**
 * @author Administrator
 * 
 */
public class TestTexturedSpinningBox {

	private TransformSceneNode rootNode;
	private RenderingContext context;
	private Frustum frustum;
	private Timer timer;

	public void render() {
		context.clear(null, null);
		context.project3D(frustum);
		context.draw(rootNode);
		context.show();
	}

	AxisAngle4f axis = new AxisAngle4f(0, 1, 1, 0);

	public void update() {
		timer.tick();
		axis.angle += Math.toRadians(timer.getTimePerFrame() * 10);

		Quat4f quat = new Quat4f();
		quat.set(axis);
		rootNode.get(0).getLocalTransform().setRotation(quat);
	}

	public void initDisplay() {
		WindowSurface surface = new WindowSurface() {

			@Override
			public void create() {
				try {
					for (DisplayMode mode : Display.getAvailableDisplayModes()) {
						if (mode.getWidth() == 640 && mode.getHeight() == 480 && mode.getBitsPerPixel() >= 24) {
							Display.setDisplayMode(mode);
							Display.setFullscreen(false);
							Display.setTitle("Test Spinning Box");
							Display.create();
							break;
						}
					}
				} catch (LWJGLException ex) {
					System.err.println(ex);
					System.exit(1);
				}
			}

			@Override
			public int getWidth() {
				return 640;
			}

			@Override
			public int getHeight() {
				return 480;
			}
		};
		PlatformManager.instantiate(new LWJGLPlatform());
		PlatformManager.instance().createWindow(surface);
		PlatformManager.instance().start();
		context = surface.getGraphicsContext();
	}

	public void initGame() {
		Color4f[] colours = new Color4f[24];
		for (int i = 0; i < colours.length; i++) {
			colours[i] = new Color4f(1, 0, 0, 0);
		}

		Point3f[] vertices = new Point3f[24];
		// front face
		vertices[0] = new Point3f(-0.5f, -0.5f, +0.5f);
		vertices[1] = new Point3f(-0.5f, +0.5f, +0.5f);
		vertices[2] = new Point3f(+0.5f, +0.5f, +0.5f);
		vertices[3] = new Point3f(+0.5f, -0.5f, +0.5f);
		// back face
		vertices[4] = new Point3f(+0.5f, -0.5f, -0.5f);
		vertices[5] = new Point3f(+0.5f, +0.5f, -0.5f);
		vertices[6] = new Point3f(-0.5f, +0.5f, -0.5f);
		vertices[7] = new Point3f(-0.5f, -0.5f, -0.5f);
		// left face
		vertices[8] = new Point3f(-0.5f, -0.5f, -0.5f);
		vertices[9] = new Point3f(-0.5f, +0.5f, -0.5f);
		vertices[10] = new Point3f(-0.5f, +0.5f, +0.5f);
		vertices[11] = new Point3f(-0.5f, -0.5f, +0.5f);

		vertices[12] = new Point3f(+0.5f, -0.5f, +0.5f);
		vertices[13] = new Point3f(+0.5f, +0.5f, +0.5f);
		vertices[14] = new Point3f(+0.5f, +0.5f, -0.5f);
		vertices[15] = new Point3f(+0.5f, -0.5f, -0.5f);
		// top
		vertices[16] = new Point3f(-0.5f, +0.5f, +0.5f);
		vertices[17] = new Point3f(-0.5f, +0.5f, -0.5f);
		vertices[18] = new Point3f(+0.5f, +0.5f, -0.5f);
		vertices[19] = new Point3f(+0.5f, +0.5f, +0.5f);

		vertices[20] = new Point3f(-0.5f, -0.5f, +0.5f);
		vertices[21] = new Point3f(-0.5f, -0.5f, -0.5f);
		vertices[22] = new Point3f(+0.5f, -0.5f, -0.5f);
		vertices[23] = new Point3f(+0.5f, -0.5f, +0.5f);

		// texture coordinates
		Vector2f[][] textureCoordinates = new Vector2f[1][24];
		for (int i = 0; i < textureCoordinates[0].length; i += 4) {
			textureCoordinates[0][i + 0] = new Vector2f(0, 0);
			textureCoordinates[0][i + 1] = new Vector2f(0, 1);
			textureCoordinates[0][i + 2] = new Vector2f(1, 1);
			textureCoordinates[0][i + 3] = new Vector2f(1, 0);
		}

		// indices
		int[] indices = new int[42];
		int faceValue = 0;
		for (int i = 0; i < indices.length; i += 6) {
			indices[i + 0] = 0 + faceValue;
			indices[i + 1] = 1 + faceValue;
			indices[i + 2] = 2 + faceValue;
			indices[i + 3] = 0 + faceValue;
			indices[i + 4] = 2 + faceValue;
			indices[i + 5] = 3 + faceValue;
			faceValue += 4;
		}

		// normals
		Vector3f[] normals = new Vector3f[24];
		// front face
		normals[0] = new Vector3f(0, 0, 1);
		normals[1] = normals[0];
		normals[2] = normals[0];
		normals[3] = normals[0];
		// back face
		normals[4] = new Vector3f(0, 0, -1);
		normals[5] = normals[4];
		normals[6] = normals[4];
		normals[7] = normals[4];
		// left face
		normals[8] = new Vector3f(-1, 0, 0);
		normals[9] = normals[8];
		normals[10] = normals[8];
		normals[11] = normals[8];
		// right face
		normals[12] = new Vector3f(1, 0, 0);
		normals[13] = normals[12];
		normals[14] = normals[12];
		normals[15] = normals[12];
		// top face
		normals[16] = new Vector3f(0, 1, 0);
		normals[17] = normals[16];
		normals[18] = normals[16];
		normals[19] = normals[16];
		// bottom face
		normals[20] = new Vector3f(0, -1, 0);
		normals[21] = normals[20];
		normals[22] = normals[20];
		normals[23] = normals[20];

		rootNode = new TransformSceneNode();
		rootNode.setLocalTransform(new Matrix4f(new Quat4f(), new Vector3f(0, 0, -6f), 1.0f));
		SceneMesh mesh = new SceneMesh(new InterleavedGeometry(vertices, normals, colours, textureCoordinates,
				indices));
		rootNode.add(mesh);

		XMLLoader<SceneMaterial> materialLoader = new XMLLoader<SceneMaterial>(new SceneMaterialXMLElement());
		materialLoader.setResourceFinder(new IResourceFinder() {

			public InputStream findResource(String name) throws IOException {
				return Thread.currentThread().getContextClassLoader().getResource(name).openStream();
			}
		});

		try {
			mesh.setSceneMaterial(materialLoader.load("test.xml", null));
		} catch (IOException ex) {
			Logger.getLogger(TestTexturedSpinningBox.class.getName()).log(Level.SEVERE, null, ex);
		}

		TextureLoader loader = new TextureLoader(new IResourceFinder() {

			public InputStream findResource(String name) throws IOException {
				return Thread.currentThread().getContextClassLoader().getResource(name).openStream();
			}
		});

		Texture tex = null;
		try {
			tex = loader.load("images/marine.dds", null);
		} catch (IOException e) {
			e.printStackTrace();
		}

		TextureRenderState texState = new TextureRenderState();
		texState.setTextures(new Texture[] { tex });
		texState.setEnabled(true);

		mesh.getSceneMaterial().getPasses().get(0).setTextureRenderState(texState);

		timer = new Timer();
	}

	public void initFrustum() {
		frustum = new Frustum(70f, 1.33333f, 1, 100);
		frustum.getTransform().setTranslation(new Vector3f(40, 0, -50));
	}

	public static void main(String args[]) {
		TestTexturedSpinningBox box = new TestTexturedSpinningBox();
		box.initDisplay();
		box.initGame();
		box.initFrustum();
		while (!Display.isCloseRequested()) {
			box.update();
			box.render();
		}

		PlatformManager.instance().destory();
	}
}
